#include "parse_strain_genotype.h"


#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/tr1/tuple.hpp>
#include <boost/spirit/home/phoenix/core/argument.hpp>
#include <boost/spirit/home/phoenix/algorithm.hpp>
#include <boost/spirit/repository/include/qi_flush_multi_pass.hpp>

#include "qi_parse_error_handler.h"

namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

using std::string;
using std::cerr;
using std::vector;


//888888888888888888888888888888888888888888888888888888888888888888888888888888
// 
//		t_strain_genotype
// 	
//888888888888888888888888888888888888888888888888888888888888888888888888888888


BOOST_FUSION_ADAPT_STRUCT(
t_strain_genotype,
(std::string,	chromosome)
(unsigned,		pos)
(char, 			ref)
(char, 			genotype1)
(char, 			genotype2)
)


phoenix::function<errorHandlerT> const errorHandler_body = errorHandlerT("Genotype per strain");


template <typename Iterator>
struct strain_genotype_grammar
: qi::grammar<Iterator, t_strain_genotype()>
{
    strain_genotype_grammar(unsigned& curr_line_number_)
    : strain_genotype_grammar::base_type(strain_genotype), curr_line_number(curr_line_number_)
    {
        using qi::lit;
        using qi::lexeme;
        using ascii::char_;
        using qi::int_;
        using ascii::string;
        using namespace qi::labels;
        using qi::eoi;
        using qi::eol;

        genotype1             %= char_("ACGTN.");  
        genotype2             %= char_("ACGTN.");  
		other_fields		  %= *char_;

        chromosome    %= +(char_ - '\t');
        position      %= int_;  
        tab           =  lit("\t");
        ref           %= char_("ACGTN");  
        strain_genotype           
					%=    	-lit("chr") > chromosome    > tab  
                            > position                  > tab  
                            > ref                       > tab  
                            > genotype1
							> genotype2
							> -other_fields
                            > -eoi;

        // give names for debug
        tab                 .name("TAB");
        chromosome          .name("Chromosome");
        position            .name("Contig position");
        ref                 .name("Reference sequence");
        strain_genotype     .name("Genotype per strain");
        genotype1           .name("Genotype 1"); 
        genotype2           .name("Genotype 2"); 
		other_fields		.name("Other fields");

		qi::on_error<qi::fail>                               
		(strain_genotype, ::errorHandler_body(_1, _2, _3, _4, phoenix::ref(curr_line_number), phoenix::ref(error_msg), true));
    }
    qi::rule<Iterator, std::string()>     	chromosome    	;   
    qi::rule<Iterator, int()>             	position      	;   
    qi::rule<Iterator, void()>            	tab           	;   
    qi::rule<Iterator, char()>     			ref           	;   
	qi::rule<Iterator, char()>            	genotype1       ;   
	qi::rule<Iterator, char()>            	genotype2       ;   
	qi::rule<Iterator, std::string()>     	other_fields   	;   
    qi::rule<Iterator, t_strain_genotype()> strain_genotype ; 
	unsigned&								curr_line_number;
	std::string error_msg;
};


sp_strain_genotype_grammar
create_strain_genotype_grammar(unsigned& curr_line_number)
{
	return sp_strain_genotype_grammar(new strain_genotype_grammar<string::const_iterator>(curr_line_number));
}


bool parse_strain_genotype(sp_strain_genotype_grammar p_strain_genotype_grammar, string::const_iterator& beg, string::const_iterator end, t_strain_genotype& res)
{
	strain_genotype_grammar<string::const_iterator>& strain_genotype_grammar = *p_strain_genotype_grammar;
    return qi::parse(beg, end, strain_genotype_grammar, res);
}
    
    
    
    
    
    
    
    
    
    
    
    
    
//888888888888888888888888888888888888888888888888888888888888888888888888888888
// 
//  	t_strain_genotype_ex
// 	
//888888888888888888888888888888888888888888888888888888888888888888888888888888

BOOST_FUSION_ADAPT_STRUCT(
t_strain_genotype_ex,
(std::string,	chromosome)
(unsigned,		pos)
(char, 			ref)
(char, 			genotype1)
(char, 			genotype2)
(int	 ,   	hcg)
(int,      		mapping_quality)
(int,      		genotype_quality)
)


phoenix::function<errorHandlerT> const errorHandler_body2 = errorHandlerT("Genotype per strain with qualities");


template <typename Iterator>
struct strain_genotype_ex_grammar
: qi::grammar<Iterator, t_strain_genotype_ex()>
{
    strain_genotype_ex_grammar(unsigned& curr_line_number_)
    : strain_genotype_ex_grammar::base_type(strain_genotype_ex), curr_line_number(curr_line_number_)
    {
        using qi::lit;
        using qi::lexeme;
        using ascii::char_;
        using qi::int_;
		using qi::uint_;
        using ascii::string;
        using namespace qi::labels;
        using qi::eoi;
        using qi::eol;

        genotype1             %= char_("ACGTN.");  
        genotype2             %= char_("ACGTN.");  

        chromosome    %= +(char_ - '\t');
        position      %= int_;  
        tab           =  lit("\t");
        ref           %= char_("ACGTN");  

		hcg				 %= int_;
		mapping_quality  %= int_;
		genotype_quality %= int_;



        strain_genotype_ex           
					%=    	-lit("chr") > chromosome    > tab  
                            > position                  > tab  
                            > ref                       > tab  
                            > genotype1
							> genotype2					> tab
							> hcg						> tab
							> mapping_quality 			> tab
							> genotype_quality
                            > -eoi;

        // give names for debug
        tab                 .name("TAB");
        chromosome          .name("Chromosome");
        position            .name("Contig position");
        ref                 .name("Reference sequence");
        strain_genotype_ex  .name("Genotype per strain");
        genotype1           .name("Genotype 1"); 
        genotype2           .name("Genotype 2"); 
		hcg             	.name("High Confidence Genotype flag"); 	
		mapping_quality 	.name("Mapping Quality Score");
		genotype_quality	.name("Genotype Quality Score");





        qi::on_error<qi::fail>                               
        (strain_genotype_ex, ::errorHandler_body(_1, _2, _3, _4, phoenix::ref(curr_line_number), phoenix::ref(error_msg), true));
    }
    qi::rule<Iterator, std::string()>     	chromosome    	;   
    qi::rule<Iterator, int()>             	position      	;   
    qi::rule<Iterator, void()>            	tab           	;   
    qi::rule<Iterator, char()>     			ref           	;   
	qi::rule<Iterator, char()>            	genotype1       ;   
	qi::rule<Iterator, char()>            	genotype2       ;   
	qi::rule<Iterator, int()>             	hcg      		;   
	qi::rule<Iterator, int()>          		mapping_quality	;   
	qi::rule<Iterator, int()>          		genotype_quality;   
    qi::rule<Iterator, t_strain_genotype_ex()> strain_genotype_ex ; 
	unsigned&								curr_line_number;
	std::string error_msg;
};


sp_strain_genotype_ex_grammar
create_strain_genotype_ex_grammar(unsigned& curr_line_number)
{
	return sp_strain_genotype_ex_grammar(new strain_genotype_ex_grammar<string::const_iterator>(curr_line_number));
}


bool parse_strain_genotype_ex(sp_strain_genotype_ex_grammar p_strain_genotype_ex_grammar, string::const_iterator& beg, string::const_iterator end, t_strain_genotype_ex& res)
{
	strain_genotype_ex_grammar<string::const_iterator>& strain_genotype_ex_grammar = *p_strain_genotype_ex_grammar;
    return qi::parse(beg, end, strain_genotype_ex_grammar, res);
}

